package com.thinkit.bigdata.web.controller.perCenter;

import com.thinkit.bigdata.web.model.result.Constants;
import com.thinkit.bigdata.web.model.sec.User;
import com.thinkit.bigdata.web.model.sec.UserExample;
import com.thinkit.bigdata.web.model.sys.SysConfig;
import com.thinkit.bigdata.web.service.sec.UserService;
import com.thinkit.bigdata.web.service.sys.SysConfigService;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;

/**
 * 用户状态相关的定时任务
 * 1、将密码输错5次锁定状态的用户 重设为正常状态
 * 2、将密码过期的用户设置为锁定状态
 * Created by lihongli on 2019/1/28
 */
@Component
public class UserStatusTask {

    private static Logger logger = LoggerFactory.getLogger(UserStatusTask.class);

    @Resource
    private UserService userService;

    @Resource
    private SysConfigService sysConfigService;

    /**
     * 用户解锁
     * <note>只解锁状态为1，且错误次数达到系统设置的用户，解锁后用户状态为0，错误次数为0</note>
     */
    @Scheduled(cron = "${cron.task.user.status:0 0 0 * * ?}")
    public void updateUserStatusNormal() {
        // 查询出来最大登录错误次数 查询锁定用户的时候 只查询出来因为密码输出错误达到5次的用户
        Integer times = 5;
        SysConfig config = sysConfigService.sysConfigGetByPK(Constants.LOGIN_MAX_FAILURE);
        try {
            // 对配置的值进行判断处理
            times = Integer.valueOf(config.getValue().trim());
        } catch (NumberFormatException e) {
            // 非数字格式转换报错 不处理 直接使用初始值
        }
        // 设置查询条件 只查询出来因为密码输出错误达到5次的用户
        UserExample example = new UserExample();
        example.createCriteria().andIsdeleteEqualTo(1).andErrornumGreaterThanOrEqualTo(times);
        // 设置更新后用户状态：正常，登录错误次数0
        User user = new User();
        user.setIsdelete(0);
        user.setErrornum(0);
        try {
            userService.updateByExampleSelective(user, example);
        } catch (Exception e) {
            logger.error("解锁用户的定时任务出现错误", e);
        }
    }

    /**
     * 将密码过期的用户设置为锁定状态
     * <note>锁定密码过期用户时 同时设置密码错误次数为0，避免出现特殊情况（密码过期且达到错误次数，锁定后又上面解锁的定时任务解锁）</note>
     */
    @Scheduled(cron = "${cron.task.user.status:0 0 0 * * ?}")
    public void updateUserStatusLocked() {
        // 系统设置的过期天数
        SysConfig config = sysConfigService.sysConfigGetByPK(Constants.PSW_MAX_DAY);
        int days = 90;
        try {
            if (null != config)
                days = Integer.valueOf(config.getValue().trim());
        } catch (NumberFormatException e) {
            logger.error("密码过期天数设置有误", e);
        }
        // 和数据库去比较的时间 数据库时间 + 设置过期天数days < 现在的时间 说明不过期 否则过期
        // 即现在的时间 往前推 days 如果小于了数据库时间 说明过期
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -days);
        Date checkTime = calendar.getTime();
        // 设置查询条件
        UserExample example = new UserExample();
        example.createCriteria().andPswsettimeLessThan(checkTime);
        // 设置更新后用户状态：2过期
        User user = new User();
        user.setIsdelete(2);
        user.setPassword(getInitPassword());
        user.setPswsettime(null);
        // 同时重置错误次数 避免解锁定时任务把密码过期的用户也给解锁了
        user.setErrornum(0);
        try {
            userService.updateByExampleForCron(user, example);
        } catch (Exception e) {
            logger.error("用户密码过期设定锁定状态的定时任务出现错误", e);
        }
    }

    /**
     * 将长时间不登录（达到设定值 默认90天）的用户锁定
     */
    @Scheduled(cron = "${cron.task.user.status:0 0 0 * * ?}")
    public void lockUserWhenNoLogin() {
        // 系统设置的过期天数
        SysConfig config = sysConfigService.sysConfigGetByPK(Constants.NO_LOGIN_DAY_LOCKED);
        int days = 90;
        try {
            if (null != config)
                days = Integer.valueOf(config.getValue().trim());
        } catch (NumberFormatException e) {
            logger.error("账号多少天不登录会被锁定设置有误", e);
        }
        // 和数据库去比较的时间 数据库时间 + 设置未登录天数days < 现在的时间 说明没达到锁定条件 否则要进行锁定
        // 即现在的时间 往前推 days 如果小于了数据库时间 说明要进行锁定
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -days);
        Date checkTime = calendar.getTime();
        // 设置查询条件
        UserExample example = new UserExample();
        // 如果上次登录时间小于了checkTime 说明已经长时间没有登录了
        example.or().andLastlogintimeLessThan(checkTime);
        // 如果上次登录时间为null，从来没登录过的，使用用户创建时间来判断 小于了checkTime 也说明已经长时间没有登录了
        example.or().andLastlogintimeIsNull().andCreatetimeLessThan(checkTime);
        // 设置更新后用户状态：1冻结
        User user = new User();
        user.setIsdelete(1);
        // 同时重置错误次数 避免解锁定时任务把密码过期的用户也给解锁了
        user.setErrornum(0);
        try {
            userService.updateByExampleSelective(user, example);
        } catch (Exception e) {
            logger.error("用户长时间不登录设置锁定状态的定时任务出现错误", e);
        }
    }

    /**
     * 获取初始化密码并加密
     *
     * @return -
     */
    private String getInitPassword() {
        // 获取保存密码信息的系统配置项
        SysConfig config = sysConfigService.sysConfigGetByPK(Constants.PASS_WORD_CODE);
        String password;
        if (config != null) {
            password = config.getValue();
        } else {
            password = Constants.INIT_PASS_WORD;
        }
        // 密码加密
        Md5Hash hash = new Md5Hash(password, "加盐", 2);//散裂2次
        return hash.toString();
    }
}
